<?php

namespace DreamCat\Array2Class\TestCases;

use DreamCat\Array2Class\Array2ClassConverter;
use DreamCat\Array2Class\Demo\Inner\Pojo3;
use DreamCat\Array2Class\Demo\Inner\Status;
use DreamCat\Array2Class\Demo\Pojo1;
use DreamCat\Array2Class\Demo\Pojo2;
use DreamCat\Array2Class\Demo\PojoAllow;
use DreamCat\Array2Class\Demo\SinglePojo;
use DreamCat\Array2Class\Demo\SpecSetter;
use DreamCat\Array2Class\Demo\WithArray;
use DreamCat\Array2Class\Demo\WithDefault;
use DreamCat\Array2Class\Demo\WithFrom;
use DreamCat\Array2Class\Demo\WithStaticPo;
use PHPUnit\Framework\TestCase;
use stdClass;

/**
 * 常规测试
 * @author vijay
 */
class NormalTest extends TestCase
{
    /** @var int 测试用例计数 */
    private static int $normalIdx = 0;

    /**
     * 测试正确情况
     * @param array $data 输入的数据
     * @param string $class 输出的类名
     * @param mixed $expect 预期的输出
     * @param array $config 转换器配置
     * @return void
     * @dataProvider normalData
     */
    public function testNormal(array $data, string $class, mixed $expect, array $config = [])
    {
        ++self::$normalIdx;
        $convert = new Array2ClassConverter();
        foreach ($config as $key => $val) {
            $fn = "set{$key}";
            $convert->$fn($val);
            self::assertEquals($val, $convert->{"is{$key}"}());
        }
        $result = $convert->convert($data, $class);
        self::assertEquals($expect, $result, "第" . self::$normalIdx . "条测试用例未通过");
    }

    /**
     * 测试用例数据
     * @return array
     */
    public static function normalData(): array
    {
        return [
            [
                [
                    "hideInt" => "32",
                    "mixed" => 53,
                    "mixedArray" => [
                        3,
                        ["ab"],
                    ],
                    "p3s" => [
                        ["name" => "ps4"],
                        ["name" => "switch"],
                    ],
                    "pojo2" => [
                        "int" => 5,
                        "ary" => [
                            "a",
                            3,
                        ],
                        "status" => null,
                    ],
                    "ignore" => 123,
                ],
                Pojo1::class,
                Pojo1::builder(
                    [
                        "hideInt" => "32",
                        "mixed" => 53,
                        "mixedArray" => [
                            3,
                            ["ab"],
                        ],
                    ]
                )
                    ->setP3s(
                        [
                            Pojo3::builder(["name" => "ps4"]),
                            Pojo3::builder(["name" => "switch"]),
                        ]
                    )
                    ->setPojo2(
                        Pojo2::builder(
                            [
                                "int" => 5,
                                "ary" => [
                                    "a",
                                    "3",
                                ],
                                "status" => null,
                            ]
                        )
                    ),
            ],
            [
                ["new" => 823],
                WithStaticPo::class,
                WithStaticPo::builder(
                    "builder",
                    [
                        "new" => 823,
                        "error" => "noConstruct",
                    ]
                ),
                [
                    "createNewProperty" => true,
                    "tryWithoutConstructor" => true,
                    "tryConstructWithParam" => false,
                ],
            ],
            [
                [
                    "ary" => [
                        "3",
                        "a",
                    ],
                    "int" => 3,
                ],
                Pojo2::class,
                Pojo2::builder(
                    [
                        "ary" => [
                            "3",
                            "a",
                        ],
                        "int" => 3,
                    ]
                ),
                ["tryCallSetter" => false],
            ],
            [
                [
                    "name" => "lal",
                    "error" => "noError",
                    "static" => "===",
                ],
                SpecSetter::class,
                SpecSetter::builder(
                    [
                        "name" => "lal",
                        "error" => "noError",
                        "static" => "===",
                    ]
                ),
            ],
            [
                ["status" => Status::SUCCESS],
                Pojo2::class,
                Pojo2::builder(["status" => Status::SUCCESS()]),
            ],
            [
                [
                    "name" => "testNo",
                    "noTip" => [
                        3,
                        ["ac"],
                    ],
                    "mixed" => [
                        ["ac" => "e"],
                        "ai",
                    ],
                ],
                Pojo3::class,
                Pojo3::builder(
                    [
                        "name" => "testNo",
                        "noTip" => [
                            3,
                            ["ac"],
                        ],
                        "mixed" => [
                            ["ac" => "e"],
                            "ai",
                        ],
                    ]
                ),
            ],
            [
                [
                    "key_word" => "key",
                    "array" => [
                        "abc",
                        "ccd",
                    ],
                    "a" => "abkkk",
                ],
                WithFrom::class,
                WithFrom::builder(
                    [
                        "keyWord" => "key",
                        "array" => new SinglePojo(
                            [
                                "abc",
                                "ccd",
                            ]
                        ),
                        "alias" => "abkkk",
                    ]
                ),
            ],
            [
                ["status" => strval(Status::SUCCESS)],
                Pojo2::class,
                Pojo2::builder(["status" => Status::SUCCESS()]),
            ],
            [
                [
                    "status" => strval(Status::SUCCESS),
                    "allNullStatus" => null,
                ],
                Pojo2::class,
                Pojo2::builder(
                    [
                        "status" => Status::SUCCESS(),
                        "allNullStatus" => null,
                    ]
                ),
            ],
            [
                [
                    "union" => 15,
                ],
                PojoAllow::class,
                PojoAllow::builder(["union" => 15]),
            ],
            [
                ["union" => 15],
                stdClass::class,
                (object)["union" => 15],
            ],
            [
                [
                    "intMap" => [
                        "ui" => 15,
                        "ui2" => 84,
                        "ui3" => 1,
                    ],
                    "unknownArray" => [
                        "4k",
                        ["re"],
                        "a",
                    ],
                ],
                WithArray::class,
                WithArray::builder(
                    [
                        "intMap" => [
                            "ui" => 15,
                            "ui2" => 84,
                            "ui3" => 1,
                        ],
                        "unknownArray" => [
                            "4k",
                            ["re"],
                            "a",
                        ],
                    ]
                ),
            ],
            [
                ["list" => 59],
                WithDefault::class,
                new WithDefault(),
            ],
        ];
    }

    /**
     * 测试回调的形式
     * @return void
     */
    public function testCallback()
    {
        $data = ["call" => uniqid("call-")];
        $expected = new Pojo2();
        $expected->setCall(
            function () use ($data) {
                return $data["call"];
            }
        );
        $convert = new Array2ClassConverter();
        $result = $convert->convert($data, Pojo2::class);
        self::assertEquals($expected, $result);
        self::assertTrue(is_callable($result->getCall()));
        self::assertEquals($data["call"], $result->getCall()());
    }

    /**
     * 测试直接输入对象
     * @return void
     */
    public function testClassObject()
    {
        $data = new SinglePojo(uniqid("pojo-"));
        $convert = new Array2ClassConverter();
        $result = $convert->convert($data, SinglePojo::class);
        self::assertEquals($data, $result);
        self::assertEquals(spl_object_id($data), spl_object_id($result));
    }
}

# end of file
